package com.uc3m.dsic.gestorZoo;

import java.io.*;
import java.sql.*;
import java.util.Collection;

/**
 * Esta clase genera los informes en HTML y EXCEL de todas las tablas que 
 * pertecenen a la base de datos zoo.
 * 
 * @author Guillermo Solano 
 * @version 1.0
 */
public class GenerarInformes extends GestorZooAplicacion {

    /**
     * Constante que define la ruta donde se almacena el fichero .xls de excel
     * creado al llamar al método de generación pertinente .
     */
    public final static String PATHXLS = "./base_de_datos_zoo.xls";
    /** 
     * Constante que define la ruta donde se almacena el fichero .html
     */
    public final static String PATHHTML = "./base_de_datos_zoo.html";
    /**
     * Constante que define un espacio vacio si una tupla se encuentra vacia.
     * Si se da este caso aparecerá este simbolo en la fila/columna respectiva
     * del documento HTML generado.
     */
    private final static String VACIO_HTML = " - ";
    /**
     * Constante que define un espacio vacio si una tupla se encuentra vacia.
     * Si se da este caso aparecerá este simbolo en la fila/columna respectiva
     * del documento EXCEL generado.
     */
    private final static String VACIO_EXCEL = "";

    /*
     * Este enumerador privado son dos estados que permiten controlar no llamar
     * a un metodo privado en el proceso de generacion html si previamente se
     * debe ejecutar otro método relacionado (por ejemplo, no se puede llamar
     * a insertarTablaHTML o al finalHTML si previamente no se ha llamado a
     * inicioHTML().
     */
    private enum Estado {

        INICIO, INSERTANDO
    };
    /**
     * variable que almacena el estado actual en el proceso de generacion de
     * un documento html.
     */
    private static Estado estadoHTML = Estado.INICIO;
    /**
     * Variable encargada de escribir en un fichero.
     */
    private PrintWriter pw;

    /**
     * Unico constructor de la clase. llama al padre.
     */
    public GenerarInformes() {
        super();
    }

// ------------- MÉTODOS GENERACION DOC EXCEL --------------------------//
    /**
     * Genera el informe EXCEL con todas las tablas incluidas en la base de
     * datos zoo.
     * 
     * @return  cierto si genero satisfactoriamente, falso en caso contrario
     */
    public boolean generarInformeZoosEXCEL() {

        String nombColums[] = super.nombresTablas();
        try {
            for (int i = 0; i < nombColums.length; i++) {
                this.generarTablasExcel(this.getED(nombColums[i]));
            }
            return true;
        } catch (Exception e) {
            //actuacion si falla el informe
            return false;
        }
    }

    /**
     * Inserta una nueva tabla en el documento EXCEL.
     *
     * @param filasTabla Coleccion de coleccion de strings. La primera coleccion
     *          hace referencia a la fila de la tabla, la segunda a la columna
     *          actual.
     * @throws ZooException si hay algun fallo en la generación del documento
     *                      EXCEL.
     */
    /* NOTA: La tabla se genera con una estructura de datos que se genera
    automaticamente llamando al metodo getED(nombre tabla) que pertenece
    a esta misma clase. */
    private void generarTablasExcel(Collection<Collection<String>> filasTabla)
            throws ZooException {

        StringBuffer temp;
        String aux;
        boolean primeraFila = true;
        /* Comprobaciones para poder ejecutar el metodo correctamente*/
        if (filasTabla == null || filasTabla.size() < 1) {
            throw new ZooException("Las filas de la tabla no contienen ni"
                    + " una fila. Verifique el parametro de entrada filasTabla");
        }
        /* fin comprobaciones */
        try {

            pw = new PrintWriter(new BufferedWriter(
                    new FileWriter(PATHXLS, true)));
            pw.println();
            /* y se insertan las filas */
            /* Para cada fila c de la tabla*/
            for (Collection<String> c : filasTabla) {

                temp = new StringBuffer();
                /* Se insertan cada atributo en la fila */
                if (primeraFila) {
                    for (String s : c) {
                        temp.append(s.toUpperCase() + "\t");
                    }
                    primeraFila = false;
                } else {
                    for (String s : c) {
                        if (s != null) {
                            temp.append(s + "\t");
                        } else {
                            temp.append(VACIO_EXCEL + "\t");
                        }
                    }
                }
                aux = temp.toString();
                //pw.println(aux.substring(0, aux.length() -2));
                pw.println(aux);
            } /* fin de la tabla */
            /* se deja un espacio para la siguiente tabla si la hubiera */
            pw.println();
            pw.println();
            pw.close(); //

        } catch (Exception e) { //error con el fichero de la BBDD
            throw new ZooException("Error generando el documento HTML" 
                    + " con la base de datos en la ruta " + PATHHTML
                    + ". Error localizado: " + e.getLocalizedMessage());
        }
    }

// ------------- MÉTODOS GENERACION DOC HTML --------------------------//
    /**
     * Genera el informe HTML con todas las tablas incluidas en la base de
     * datos zoo.
     * 
     * @return  cierto si genero satisfactoriamente, falso en caso contrario
     */
    public boolean generarInformeZoosHTML() {

        String nombColums[] = super.nombresTablas();
        try {
            this.inicioHTML();
            for (int i = 0; i < nombColums.length; i++) {
                this.doTablasHTML(this.getED(nombColums[i]), nombColums[i]);
            }
            this.finalHTML();
            return true;
        } catch (Exception e) {
            //actuacion si falla el informer
            return false;
        }
    }

    /**
     * Genera el inicio de  un documento HTML. Se debe llamar una vez al 
     * principio de la generacion del informe y no se puede volver a llamar 
     * hasta llamar al metodo finHTML.
     * 
     * @throws ZooException Si se ha llamado previamente a este método pero no
     *                  no se ha llamado a finHTML().
     */
    private void inicioHTML() throws ZooException {

        if (estadoHTML != Estado.INICIO) {
            throw new ZooException("Ya ha llamado inicioHTML. Para insertar" 
                    + " tablas en el HTML debe llamar al método doTablasHTML "
                    + "y/o acabar llamando al metodo finalHTML para finaliar"
                    + " la generacion del archivo HTML.");
        }
        try {
            pw = new PrintWriter(new BufferedWriter(new FileWriter(PATHHTML)));
            /*inicio documento html */
            pw.println("<html>");
            pw.println("<body>");
            /* pasamos al siguiente estado */
            estadoHTML = Estado.INSERTANDO;
            pw.close(); //lo cerramos para que no dependa de la funcion.
            //se debe volver a abrir
        } catch (Exception e) { //error con el fichero de la BBDD
            throw new ZooException("Error generando el documento HTML"
                    + " con la base de datos en la ruta " + PATHHTML);
        }
    }

    /*
    El siguiente metodo es el que va insertando tablas en el documento HTML.
    Para hacerlo generico su funcionamiento puede ser un poco lioso a priori.

    Un ejemplo: Supongamos la siguiente tabla EDAD
    NOMBRE      | EDAD
    Guillermo      26
    pepe           12

    Entonces los parametros de entrada serían:

    filasTabla = Collection { {NOMBRE, EDAD}, {Guillermo, 26}, {pepe, 12} };
    nombreTabla = EDAD
     */
    /* NOTA: La tabla se genera con una estructura de datos que se genera
    automaticamente llamando al metodo getED(nombre tabla) que pertenece
    a esta misma clase. */
    /**
     * Inserta todas las filas para cada tabla especificada. Este método se 
     * se puede llamar despues de haber ejecutado inicioHTML y se puede llamar
     * tantas veces como tablas se desee insertan en el documento HTML. Cada
     * vez que se llama generará una nueva tabla en HTML en el documento.
     * 
     * @param filasTabla  Coleccion de filas que compone una tabla. Cada fila
     *                  a su vez es una coleccion de String, cada elemento 
     *                  representa un atributo en la tabla.
     * @param nomColumnas  Coleccion de los nombres de las columnas de la tabla
     * @param idtabla     identificador de la tabla
     * @throws ZooException Si no se ha llamado previamente al metodo inicioHTML
     *              o la coleccion de nombres de las columnas esta vacio
     *              o no hay filas en la coleccion de filas de la tabla
     *              0 el número de columnas no coincide el numero de campos
     *              por fila
     */
    private void doTablasHTML(Collection<Collection<String>> filasTabla,
            String nombreTabla)
            throws ZooException {

        StringBuffer temp;
        boolean primeraFila = true;
        /* Comprobaciones para poder ejecutar el metodo correctamente*/
        if (estadoHTML != Estado.INSERTANDO) {
            throw new ZooException("Antes de insertar tablas debe generar el"
                    + " inicio del fichero HTML llamando al metodo inicioHTML");
        } else if (filasTabla == null || filasTabla.size() < 1) {
            throw new ZooException("Las filas de la tabla no contienen ni" 
                    + " una fila. Verifique el parametro de entrada filasTabla");
        }
        /* fin comprobaciones */
        try {
            pw = new PrintWriter(new BufferedWriter(
                    new FileWriter(PATHHTML, true)));//concatena

            // se obtiene el nombre de la tabla
            pw.println("<h1> TABLA " + nombreTabla.toUpperCase() + " </h1>");
            pw.println("<br>");
            /* Ahora comienza la tabla en html */
            pw.println("<table border cellpadding=8>");

            /* y se insertan las filas */
            /* Para cada fila c de la tabla*/
            for (Collection<String> c : filasTabla) {

                temp = new StringBuffer("<tr>");
                /* Se insertan cada atributo en la fila */
                if (primeraFila) {
                    for (String s : c) {
                        temp.append("<td><b>" + s.toUpperCase() + "</b></td>");
                    }
                    primeraFila = false;
                } else {
                    for (String s : c) {
                        if (s != null) {
                            temp.append("<td>" + s + "</td>");
                        } else {
                            temp.append("<td>" + VACIO_HTML + "</td>");
                        }
                    }
                }
                pw.println(temp.toString() + "</tr>");
            }
            /* fin de la tabla */
            pw.println("</table>");
            /* se deja un espacio para la siguiente tabla si la hubiera */
            pw.println();
            pw.println();
            pw.close(); //ERROR 1. 2 MIN

        } catch (Exception e) { //error con el fichero de la BBDD
            throw new ZooException("Error generando el documento HTML" 
                    + " con la base de datos en la ruta " + PATHHTML);
        }
    }

    /**
     * Concatena al fichero HTML que esta siendo generado el cierre del fichero
     * HTML.
     * @throws ZooException Si no se ha llamado previamente a inicioHTML
     */
    private void finalHTML() throws ZooException {

        if (estadoHTML != Estado.INSERTANDO) {
            throw new ZooException("Para añadir el final del documento"
                    + " HTML debe haber llamado antes al metodo inicioHTML");
        }
        try {
            pw = new PrintWriter(new BufferedWriter(
                    new FileWriter(PATHHTML, true))); //concatenado
            /* fin documento html */
            pw.println("</body>");
            pw.println("</html>");
            pw.close();
            /* volvemos a cambiar el estado por si se genera otro informe */
            estadoHTML = Estado.INICIO;

        } catch (Exception e) { //error con el fichero de la BBDD
            throw new ZooException("Error generando el documento HTML"
                    + " con la base de datos en la ruta " + PATHHTML);
        }
    }

    /**
     * Genera una estructura de datos con toda las filas contenidas en la
     * tabla especificada por parametro.
     * @param nombreTabla nombre de la tabla que se desea emplear para generar
     *  la estructura de datos.
     * @return  La primera coleccion hace referencia a la fila de la tabla,
     *          la segunda a la columna actual.
     * @throws ZooException Si no el nombre introducido por parametro no
     *          coincide con el nombre de una tabla de la base de datos zoo.
     * @throws SQLException  Si se produce un error con la consulta SQL
     */
    /*NOTA: los nombres de las tablas vienen definidas en la constante
    GestorZooAplicacion.TABLAS_BD*/
    public Collection<Collection<String>> getED(String nombreTabla)
            throws ZooException, SQLException {
        if (nombreTabla != null) {
            return super.getEDTabla(super.getEnumTabla(nombreTabla));
        } else {
            return null;
        }
    }
    //pruebas
    /*
    public static void main (String arg[]) throws Exception{
    GenerarInformes zoo = new GenerarInformes();
    zoo.generarInformeZoosHTML();
    zoo.generarInformeZoosEXCEL();
    System.out.println("INFORMES GENERADOS SATISFACTORIAMENTE");
    }
     */
}
